package com.xf.day06

import org.apache.spark.{SparkConf, SparkContext}

/**
 * 简单来说，闭包是一个函数，它捕获了其定义环境中的自由变量（Free Variable），并且能够在其被调用时访问这些变量的值。
 * 我们来分解这个概念：
 *
 * 1. 自由变量 (Free Variable)
 *    一个变量如果在一个函数内部被使用，但不是该函数的参数，也不是在函数内部定义的局部变量，那么这个变量就被称为“自由变量”。
 * 2. 捕获环境
 *    当一个函数引用了其外部作用域中的自由变量时，Scala 编译器会“捕获”这些变量，并将它们与函数体一起打包。这样，即使外部作用域已经结束，这个函数仍然可以访问那些被捕获的变量。
 */
object Testclosure {

  def main(args: Array[String]): Unit = {

    /**
     * 累加器的工作原理：
     * 累加器是 Spark 的一种共享变量。
     * Driver 创建累加器，其值初始为 0。
     * Executor 在执行 Task 时，可以对累加器进行 add 操作。
     * Spark 保证：所有 Executor 的更新会 安全地聚合回 Driver。
     * 只能 “累加”（向 Driver 发送增量），不能读取（Executor 不能读取当前值）。
     */
    val conf = new SparkConf().setAppName("debug").setMaster("local[*]")
    val sc = new SparkContext(conf)
    val counter = sc.longAccumulator("MyCounter")  // 创建累加器
    val data = Array(1, 2, 3, 4, 5)
    sc.parallelize(data).foreach(x => counter.add(x))
    println(counter.value)  // 输出 15

   //  testSparkClosure()
  }

  private def testSparkClosure(): Unit = {
    val conf = new SparkConf().setAppName("debug").setMaster("local[*]")
    val sc = new SparkContext(conf)

    var counter = 0
    val data = Array(1, 2, 3, 4, 5)
    sc.parallelize(data).foreach(x => counter += x)
    println(counter)
  }

  private def testClosureMethod1(): Unit = {
    var x: Int = 10

    // 闭包
    def getSum(y: Int) = println(x + y)

    getSum(6)
  }
}
